Design-system hardening, accessibility follow-through, and agent UI exemplars#131
Design-system hardening, accessibility follow-through, and agent UI exemplars#131
Conversation
…FileUpload - Add `reducedMotion` companion object to `packages/tokens/src/enhanced/motion.ts` with zero-duration per-token overrides and a `cssBlock` helper for `@media (prefers-reduced-motion: reduce)` rules - Export `reducedMotion` from `packages/tokens/src/index.ts` - Add `motion-reduce:animate-none` to all production spinner/pulse animations: Button, Checkbox, Switch, EmptyMessage, Indicator, ListItem, MessageActions, CodeBlock, Markdown, chart, Progress, AlertDialog, toast, FileUpload, RangeSlider, TagInput, ModeSelector, ModelBadge, ViewModeToggle, carousel, Sidebar, command, modal - Wire `aria-live="polite"` + `aria-atomic="true"` status region to FileUpload so screen readers announce file selection and rejection results - Add vendor-risk doc for Apps SDK UI dependency (`docs/risks/APPS_SDK_VENDOR_RISK.md`) - Update design audit report (`reports/design-audit.html`) with resolved findings - Fix Biome lint: template literals, arrow functions, optional chaining, font-family HTML escaping, empty CSS block, alignment whitespace, indentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ock, RangeSlider, Pagination, SegmentedControl Combobox - Remove misused role="combobox" from trigger button (disclosure button pattern, not ARIA combobox) - Add aria-controls linking trigger → listbox; add id on listbox element - Add id on each option; add aria-activedescendant + aria-autocomplete="list" to search input so screen readers announce the highlighted option during keyboard navigation TagInput - Wrap in role="group" with aria-label for composite widget semantics - Label the text input via aria-label; add aria-invalid + aria-describedby for error - Add role="status" aria-live="polite" region to announce tag add/remove to screen readers - Render inline error message element linked by aria-describedby RangeSlider - Move aria-invalid from wrapper div to the focusable <input type="range"> - Add aria-describedby on input pointing to rendered error paragraph - Add visible error message element; remove stale aria-invalid from wrapper Carousel - Add aria-label (default "Content slideshow") to role="region" so it is a meaningful landmark Pagination - Explicit aria-hidden="true" on PaginationEllipsis (was bare aria-hidden) SegmentedControl - Wrap icon in aria-hidden="true" span to prevent double-announcement alongside label text CodeBlock (line numbers) - Change line-number <td> to <th scope="row"> for correct table semantics - Add visually-hidden <caption> so AT announces the table purpose Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ements
Adds optional `index` (0-based) and `total` props to CarouselItem.
When both are provided, aria-label="N of total" is rendered on the
role="group" slide element so screen readers announce slide position
("1 of 5", "2 of 5", etc.) per the ARIA carousel pattern.
Existing usage without these props is unaffected — aria-label is only
applied when both values are present.
Usage:
{items.map((item, i) => (
<CarouselItem key={item.id} index={i} total={items.length}>
...
</CarouselItem>
))}
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TextLink: add sanitizeHref() with protocol allow-list (https, http, mailto, tel, relative paths). Dangerous protocols like javascript: and data: render as inert anchors (no href attribute). - Markdown: apply sanitizeHref() at parse boundary before passing extracted URLs to TextLink — closes the XSS path through untrusted markdown content. - Combobox: restore role="combobox" on trigger button (select-only combobox ARIA pattern) — fixes 31 test failures from incorrect a11y removal. - Security report: reports/security_best_practices_report.md (OWASP A03). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Typography (baseline-ui rules): - Markdown h1/h2/h3: add text-balance - Markdown p: add text-pretty - EmptyMessage h3: add text-balance - EmptyMessage description p: add text-pretty - ErrorBoundary h3: add text-balance - Modal h2: add text-balance - Card h4 (CardTitle): add text-balance via cn default Layout: - toast: max-h-screen → max-h-dvh (dynamic viewport height for mobile browsers) Note: toast z-[100] flagged as a design-system concern (no built-in z-100 Tailwind token) — deferred to a separate design-system discussion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wraps the search state in useDeferredValue so the input field updates immediately while the filtered options list can defer its re-render. This keeps the combobox responsive when filtering large option lists. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a semantic zIndex extension to the Tailwind preset, backed by the existing --ds-z-* CSS custom properties from enhanced.css. Enables use of z-modal-backdrop, z-modal, z-popover, z-tooltip, etc. as Tailwind utilities instead of arbitrary z-[n] values. - toast: z-[100] → z-modal-backdrop (first component migrated) Note: existing components using z-50 for overlays/popovers/tooltips pre-date this scale and remain at z-50 for now. A broader migration to z-popover / z-tooltip is tracked as a follow-up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents that ChartStyle uses an unsafe innerHTML escape hatch, which inputs are sanitized (id, color values, config keys), and that ChartConfig must be developer-controlled — not populated from untrusted user input without explicit sanitization. Closes SEC-03 from the audit report. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- alert: add warning/success/info variants wired to existing status tokens - alert: fix AlertTitle ref type (HTMLParagraphElement → HTMLHeadingElement) - button: remove aria-invalid on <button> (invalid per ARIA spec) - button: add micro-interactions (hover scale 1.01 / active scale 0.98) with motion-reduce overrides - tokens: add transitionDuration and transitionTimingFunction to Tailwind preset (ds-micro → ds-complex, ds-swift/standard/ease-*) - focus: scope focusVisibleCSS from bare :focus-visible to .ds-focusable / [data-ds-focusable] to prevent global style conflicts; add @warning JSDoc Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ecurity report - testing/utils: pass `baseElement.ownerDocument` to userEvent.setup() instead of relying on globalThis.document, which user-event@14 captures at module load time (before jsdom initialises in vitest 4). Root cause: defaultOptionsDirect caches globalThis.document=undefined; our fix bypasses the cache using the live DOM. - Add happy-dom devDep (installed, kept for optional future use) - reports: append 2026-03-23 security review findings (S-01 to S-04) to existing report Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire the March 2026 agent-UI contract into policy, migrate protected settings and chat surfaces onto semantic design-system patterns, expand exemplar and visual coverage, and ratchet additional Storybook learning surfaces away from foundation-token usage. Co-authored-by: Codex <noreply@openai.com> EOF git pull --rebase origin main git switch -c codex/agent-ui-hardening-mar-2026 git push -u origin codex/agent-ui-hardening-mar-2026 gh pr create --fill --base main --head codex/agent-ui-hardening-mar-2026
Update stale ChatSidebar, Button, Select, ScrollArea, and touch-target policy tests to match the new semantic sizing and focus-ring classes introduced by the design-system hardening pass. Co-authored-by: Codex <noreply@openai.com> EOF git push -u origin codex/agent-ui-hardening-mar-2026 gh pr create --fill --base main --head codex/agent-ui-hardening-mar-2026
|
Required keyword not found in PR title or description. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d02d747b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const mobileBreakpointRem = mobileBreakpointPx / 16; | ||
| const isMobile = useMediaQuery(`(max-width: ${mobileBreakpointRem}rem)`); |
There was a problem hiding this comment.
Preserve mobileBreakpointPx in pixel units
mobileBreakpointPx is still the public prop name/default (768) but this change converts it to rem before building the media query. That makes the breakpoint depend on the root font size (e.g., 20px root turns 768 into a 960px breakpoint), so hosts that pass pixel values will see sidebar/mobile behavior switch at the wrong widths. Keep the query in px (or rename the API to rem) to avoid this regression.
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| const slug = pathname.replace("/template-widget/", ""); | ||
| return slug ? decodeURIComponent(slug) : undefined; |
There was a problem hiding this comment.
Catch URI decode failures for template-widget slugs
This decodeURIComponent is executed during routing without error handling, so malformed percent-encoded paths (for example /template-widget/%E0%A4%A) will throw a URIError during render and crash the route instead of showing a fallback state. Wrap slug decoding in a try/catch and return undefined (or a safe fallback) on invalid input.
Useful? React with 👍 / 👎.
Align packages/ui, packages/widgets, and packages/cloudflare-template back to the root workspace version so sync:versions:check passes again in CI. Co-authored-by: Codex <noreply@openai.com> EOF git push
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Pin Storybook Playwright visuals to en-US and UTC, and force the fullscreen chat/settings exemplar stories onto the exact 1280x720 capture surface inside storybook-visual.spec.ts so Ubuntu CI does not drift from the committed fullscreen baselines because of runner locale, timezone, or dvh/overflow quirks. Co-authored-by: Codex <noreply@openai.com>
Move the always-on exemplar evaluation step from the Ubuntu web build to the macOS build lane so the Storybook and fullscreen chat/settings screenshots are checked on the same platform their committed baselines were recorded on. Co-authored-by: Codex <noreply@openai.com>
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
Keep the token regeneration path from clobbering the semantic elevation API in packages/tokens/src/shadows.ts. The DTCG source only defines the legacy shadow map, so sync-dtcg must re-emit elevation and ElevationToken or CI breaks after pnpm generate:tokens rewrites the file. Co-authored-by: Codex <noreply@openai.com> EOF git push
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 91e718fe28
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "packages/ui/src/app/**/*.{ts,tsx,js,jsx,css}", | ||
| "platforms/web/apps/web/src/pages/**/*.{ts,tsx,js,jsx,css}", | ||
| "packages/ui/src/components/ui/**/*.{ts,tsx,js,jsx,css}", |
There was a problem hiding this comment.
Make test/spec exemptions override warn scope globs
The new warn scopes are more specific than the broad **/*.test.* and **/*.spec.* exempt globs, and findBestScopeMatch chooses the most specific match before precedence; as a result, test files are still linted as warnings (for example Chart.test.tsx warnings are emitted by design-system-guidance:check:ci) despite being listed under scopes.exempt. This can cause touched-file ratchet failures on test-only changes that should be exempt.
Useful? React with 👍 / 👎.
Use the stronger secondary text token for the template-browser description and the harness modal helper copy so the web Axe checks pass again in CI. Co-authored-by: Codex <noreply@openai.com> EOF git push
Summary
Validation
lint,typecheck, andpackages/uitestsCurrent CI Blocker
build (ubuntu-latest)andbuild (macos-latest)are failing onpnpm sync:versions:checkpackages/ui:0.1.0expected0.0.1packages/widgets:0.0.2expected0.0.1packages/cloudflare-template:0.0.2expected0.0.1Reviewer Notes
origin/main, not only the final agent-UI hardening commit